All files / src/hooks useAuth.ts

0% Statements 0/49
0% Branches 0/14
0% Functions 0/7
0% Lines 0/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                                                                                                                                                                                                                                                             
// Authentication hook
 
'use client';
 
import { useState, useEffect, useCallback } from 'react';
import { authService } from '@/services';
import { authCleanup } from '@/utils/authCleanup';
import { User, LoginRequest, UserRole } from '@/types';
import { normalizeRole } from '@/utils/auth';
 
interface UseAuthReturn {
  user: User | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  login: (credentials: LoginRequest) => Promise<{ success: boolean; error?: string }>;
  logout: () => Promise<void>;
  hasRole: (role: UserRole) => boolean;
  hasAnyRole: (roles: UserRole[]) => boolean;
}
 
export function useAuth(): UseAuthReturn {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);
 
  const isAuthenticated = !!user;
 
  // Initialize auth state
  useEffect(() => {
    const initAuth = () => {
      try {
        const storedUser = authService.getStoredUser();
        const hasToken = authService.isAuthenticated();
        
        if (storedUser && hasToken) {
          // Normalize stored user role and ensure defaults
          const roleNormalized = normalizeRole((storedUser as any).role as any);
          const userWithDefaults: User = {
            ...(storedUser as any),
            role: roleNormalized,
            active: (storedUser as any).active ?? true,
            created_at: (storedUser as any).created_at ?? new Date().toISOString()};
          setUser(userWithDefaults);
        }
      } catch (err) {
        console.error('Error initializing auth:', err);
        // Clear potentially corrupted data
        authService.clearStoredUser();
      } finally {
        setIsLoading(false);
      }
    };
 
    initAuth();
  }, []);
 
  const login = useCallback(async (credentials: LoginRequest) => {
    setIsLoading(true);
    
    try {
      const result = await authService.login(credentials);
      
      if (result.success) {
        const { token, user: userData } = result.data;
        
        // Store auth data
        authService.setAuthToken(token);
        authService.setStoredUser(userData);
 
        // Convert UserInfo to User format
        const userWithDefaults: User = {
          ...userData,
          active: true,
          created_at: new Date().toISOString()};
        setUser(userWithDefaults);
        
        return { success: true };
      } else {
        return { 
          success: false, 
          error: result.error.details || 'Login failed' 
        };
      }
    } catch {
      return {
        success: false,
        error: 'An unexpected error occurred during login'
      };
    } finally {
      setIsLoading(false);
    }
  }, []);
 
  const logout = useCallback(async () => {
    setIsLoading(true);
    
    try {
      // Call logout API (will clear token regardless of response)
      await authService.logout();
    } catch (err) {
      console.error('Logout API error:', err);
    } finally {
      // Always clear local state
      authService.clearStoredUser();
      authCleanup.clearAllAuthData();
      setUser(null);
      setIsLoading(false);
    }
  }, []);
 
  const hasRole = useCallback((role: UserRole): boolean => {
    return user?.role === role;
  }, [user]);
 
  const hasAnyRole = useCallback((roles: UserRole[]): boolean => {
    return user ? roles.includes(user.role) : false;
  }, [user]);
 
  return {
    user,
    isAuthenticated,
    isLoading,
    login,
    logout,
    hasRole,
    hasAnyRole};
}